package com.jt.aop;

import com.jt.annotation.CacheFind;
import com.jt.util.ObjectMapperUtil;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import redis.clients.jedis.Jedis;
import redis.clients.jedis.JedisCluster;
import redis.clients.jedis.JedisSentinelPool;
import redis.clients.jedis.ShardedJedis;

import java.awt.*;
import java.util.Arrays;

@Aspect  //标识我是一个切面
@Component //将对象将给spring容器管理
public class CacheAOP {

    @Autowired
//    private Jedis jedis;  redis单台测试
//    private ShardedJedis jedis;
//    private JedisSentinelPool sentinelPool;
    private JedisCluster jedis;

    /**
     * 实现思路：
     * 1.动态的获取key  用户自定义的前缀+用户参数
     * 2.判断key是否存在:
     * (如果存在:直接在redis中获取数字 JSON,需要将json转化为具体对象 按照返回值类型进行转换)
     * (如果不存在:在执行目标方法,获得返回值数据,将返回值结果转换为JSON格式,之后保存到缓存中)
     *
     * @param joinPoint
     * @return
     */

    @Around("@annotation(cacheFind)")
    public Object around(ProceedingJoinPoint joinPoint, CacheFind cacheFind) {
//        Jedis jedis = sentinelPool.getResource();
        Object result = null;
        //1.获取key的前缀
        String key = cacheFind.key();
        //2.获取方法参数
        String argString = Arrays.toString(joinPoint.getArgs());
        key = key + "::" + argString;
        System.out.println(key);
        try {
            //3.判断缓存中是否有数据
            if (jedis.exists(key)) {
                String json = jedis.get(key);
                //5.获取返回值类型
                MethodSignature methodSignature = (MethodSignature) joinPoint.getSignature();
                result = ObjectMapperUtil.toObject(json, methodSignature.getReturnType());
                System.out.println("AOP查询redis缓存");
            } else {
                //表示缓存中没有数据
                result = joinPoint.proceed();
                String json = ObjectMapperUtil.toJSON(result);
                //4.判断数据中是否有超时时间
                if (cacheFind.seconds() > 0) {
                    jedis.setex(key, cacheFind.seconds(), json);
                } else {
                    jedis.set(key, json);
                }
                System.out.println("AOP执行数据库调用!");
            }
        } catch (Throwable throwable) {
            throwable.printStackTrace();
            throw new RuntimeException(throwable);
        }
        System.out.println("环绕通知结束");
//        jedis.close();
        return result;
    }


    //切面 = 切入点表达式 + 通知方法
    //表达式1:ItemCatServiceImpl
//    @Pointcut("bran(itemCatServiceImpl)")
//    @Pointcut("within(com.jt.service.*)")
    //.*一级包下的类 ..*所有子孙后代的包和类
    //返回值类型任意,com.jt.service包下所有的类的add方法参数类型任意类型
    //写参数类型时注意类型的大小写
  /*  @Pointcut("execution(* com.jt.service..*.*(long))")
    public void pointcut() {
 } */

    /*
     *joinPoint=代表连接点对象

    @Before("pointcut()")
    public void before(JoinPoint joinPoint) {
        //1.获取目标对象
        Object target = joinPoint.getTarget();
        //2.获取目标对象的路径 包名.类名.方法名
        String className = joinPoint.getSignature().getDeclaringTypeName();
        String methodName = joinPoint.getSignature().getName();
        System.out.println("目标方法的路径" + (className + "." + methodName));
        //3.获取参数类型
        System.out.println(Arrays.toString(joinPoint.getArgs()));
    }

    @Around("pointcut()")
    public Object around(ProceedingJoinPoint joinPoint) {
        System.out.println("环绕通知执行");
        Object data = null;
        try {
            data = joinPoint.proceed(); //执行目标方法
        } catch (Throwable throwable) {
            throwable.printStackTrace();
        }
        return data;
    }
*/
}
